using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web.UI.WebControls;
using Sedna.Core.Controller;
using Sedna.Core.Controls.Enum;

namespace Sedna.Core.Controls.Command
{
    /// <summary>
    /// Saves file to directory located on server
    /// </summary>
    public class UploadToDirectoryCommand : IFileUploadCommand, ICloneable
    {
        public delegate void SuccessEvent(UploadToDirectoryCommand command, String src, FileInfo f);
        public delegate void ExceptionEvent(UploadToDirectoryCommand command, String src, Exception exception);

        private String saveAs;
        private String directory;

        private FileUploadMode fileUploadMode = FileUploadMode.ThrowException;
        private bool createDirectory;
        
        private SuccessEvent onSuccess = null;
        private ExceptionEvent onException;

        # region Properties

        public string SaveAs
        {
            get { return saveAs; }
            set { saveAs = (value == null) ? "" : value.Trim(); }
        }

        public string Directory
        {
            get { return directory; }
            set { directory = value; }
        }

        public FileUploadMode FileUploadMode
        {
            get { return fileUploadMode; }
            set { fileUploadMode = value; }
        }

        public bool CreateDirectory
        {
            get { return createDirectory; }
            set { createDirectory = value; }
        }

        public SuccessEvent OnSuccess
        {
            set { onSuccess = value; }
        }

        public ExceptionEvent OnException
        {
            set { onException = value; }
        }

        # endregion

        public FileInfo Execute(System.Web.UI.WebControls.FileUpload control)
        {
            String fileName = control.FileName;

            if (fileName == null || fileName.Trim().Length == 0)
                throw new ArgumentException("File path cannot be empty");

            if (String.IsNullOrEmpty(saveAs))
                saveAs = fileName;

            if (!System.IO.Directory.Exists(directory))
            {
                if (!createDirectory)
                    throw new DirectoryNotFoundException(String.Format("Directory '{0}' not found", directory));

                System.IO.Directory.CreateDirectory(directory);
            }

            String path = String.Format("{0}/{1}", directory, saveAs);
            
            BufferedStream output = null;

            Exception e = null;

            try
            {
                if (File.Exists(path))
                {
                    switch (fileUploadMode)
                    {
                        case Enum.FileUploadMode.ThrowException:
                            {
                                throw new Exception(String.Format("File '{0}' already exists", path));
                            }
                        case Enum.FileUploadMode.AutoIncrement:
                            {
                                int i = 1;
                                
                                FileInfo f = new FileInfo(path);
                                
                                String fName = f.Name;
                                String fExt = f.Extension;

                                if (fName.IndexOf(fExt) == (fName.Length - fExt.Length))
                                    fName = fName.Substring(0, (fName.Length - fExt.Length));                                                                
                                
                                do
                                {
                                    path = String.Format("{0}/{1}[{2}].{3}", directory, fName, i, fExt);
                                    i++;
                                }
                                while (File.Exists(path));
                                
                                break;
                            }
                    }
                }
                
                output = new BufferedStream(new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite));
                
                byte[] buff = new byte[1024];
                
                int count = 0;

                while ((count = control.PostedFile.InputStream.Read(buff, 0, 1024)) > 0)
                {
                    output.Write(buff, 0, count);
                }
                
                output.Flush();                                                
            }
            catch(Exception ex)
            {                                
                e = ex;
            }
            finally
            {
                if (output != null)
                    output.Close();
            }
            
            if (e != null)
            {
                if (onException != null)
                    onException(this, fileName, e);
                else 
                    throw e;

                return null;
            }

            FileInfo result = new FileInfo(path);
            
            if (onSuccess != null)
                onSuccess(this, fileName, result);

            return result;
        }

        public object Clone()
        {
            return MemberwiseClone();
        }
    }
}
